page.tsx 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { getTranslations, setRequestLocale } from "next-intl/server";
  2. import { Link } from "@/i18n/navigation";
  3. import { courses, type CourseCategory } from "@/data/courses";
  4. import { SectionHeading } from "@/components/section-heading";
  5. import { IconBook, IconChart, IconShield } from "@/components/icons";
  6. import { HomeHeroCarousel } from "@/components/home-hero-carousel";
  7. type Props = { params: Promise<{ locale: string }> };
  8. export default async function HomePage({ params }: Props) {
  9. const { locale } = await params;
  10. setRequestLocale(locale);
  11. const t = await getTranslations("home");
  12. const tc = await getTranslations("courses");
  13. const featured = courses.slice(0, 5);
  14. const featuredCoverMap: Record<CourseCategory, string> = {
  15. trial: "/免费试听--状态--锁定、解锁.png",
  16. practical: "/系统课程--状态--锁定、解锁.png",
  17. book: "/拆书章节视频--状态--锁定、解锁.png",
  18. topic: "/专题视频-状态--锁定、解锁.png",
  19. strategy: "/策略报告--状态--锁定、解锁.png",
  20. };
  21. const stats = [
  22. { value: t("stat1"), label: t("stat1Label") },
  23. { value: t("stat2"), label: t("stat2Label") },
  24. { value: t("stat3"), label: t("stat3Label") },
  25. { value: t("stat4"), label: t("stat4Label") },
  26. ];
  27. const pillars = [
  28. {
  29. icon: IconBook,
  30. title: t("pillar1Title"),
  31. desc: t("pillar1Desc"),
  32. accent: "from-blue-500 to-indigo-600",
  33. },
  34. {
  35. icon: IconChart,
  36. title: t("pillar2Title"),
  37. desc: t("pillar2Desc"),
  38. accent: "from-amber-500 to-orange-600",
  39. },
  40. {
  41. icon: IconShield,
  42. title: t("pillar3Title"),
  43. desc: t("pillar3Desc"),
  44. accent: "from-emerald-500 to-teal-600",
  45. },
  46. ];
  47. const heroBanners = ["/banner1.png", "/banner2.png", "/banner3.png", "/banner4.png", "/banner5.png"];
  48. return (
  49. <div>
  50. {/* Hero:左文案 + 右轮播 + 统一背景 */}
  51. <section className="ui-enter relative overflow-hidden border-b border-slate-200/80 bg-gradient-to-br from-slate-900 via-[#0f1b2d] to-slate-900 text-white">
  52. <div className="hero-grid pointer-events-none absolute inset-0 z-0 opacity-40" />
  53. <div className="pointer-events-none absolute -right-16 top-16 z-0 h-72 w-72 rounded-full bg-blue-500/18 blur-3xl" />
  54. <div className="pointer-events-none absolute -left-20 bottom-8 z-0 h-64 w-64 rounded-full bg-amber-500/12 blur-3xl" />
  55. <div className="site-container relative z-10 grid gap-10 py-16 md:grid-cols-2 md:items-center md:py-20 lg:gap-14">
  56. <div className="max-w-xl md:pr-4">
  57. <p className="text-sm font-semibold tracking-wide text-amber-300/95">
  58. {t("heroEyebrow")}
  59. </p>
  60. <h1 className="font-serif mt-4 text-4xl font-bold leading-[1.12] tracking-tight text-white md:text-5xl lg:text-[3.15rem]">
  61. {t("heroTitle")}
  62. </h1>
  63. <p className="mt-5 max-w-lg text-base leading-relaxed text-slate-200 md:text-lg">
  64. {t("heroSubtitle")}
  65. </p>
  66. <div className="mt-8 flex flex-wrap items-center gap-4">
  67. <Link
  68. href="/courses"
  69. className="ui-interactive-btn inline-flex min-w-[130px] items-center justify-center rounded-full bg-gradient-to-r from-amber-400 to-amber-500 px-7 py-3 text-sm font-bold text-[var(--navy)] shadow-xl shadow-amber-500/20 transition hover:from-amber-300 hover:to-amber-400"
  70. >
  71. {t("ctaCourses")}
  72. </Link>
  73. <Link
  74. href="/about"
  75. className="ui-interactive-btn inline-flex min-w-[130px] items-center justify-center rounded-full border border-white/35 bg-white/8 px-7 py-3 text-sm font-semibold text-white transition hover:border-white/55 hover:bg-white/12"
  76. >
  77. {t("ctaAbout")}
  78. </Link>
  79. </div>
  80. </div>
  81. <div className="relative w-full md:justify-self-end md:pl-4">
  82. <div className="w-full md:max-w-[720px]">
  83. <HomeHeroCarousel images={heroBanners} />
  84. </div>
  85. </div>
  86. </div>
  87. {/* 数据条 */}
  88. <div className="relative z-10 border-t border-white/10 bg-black/20">
  89. <div className="site-container grid grid-cols-2 gap-6 py-8 md:grid-cols-4">
  90. {stats.map((s) => (
  91. <div key={s.label} className="text-center md:text-left">
  92. <p className="font-serif text-3xl font-bold text-white md:text-4xl">{s.value}</p>
  93. <p className="mt-1 text-sm text-slate-400">{s.label}</p>
  94. </div>
  95. ))}
  96. </div>
  97. </div>
  98. </section>
  99. {/* 三大支柱 */}
  100. <section className="ui-enter ui-enter-delay-1 site-container section-block">
  101. <SectionHeading
  102. eyebrow={t("pillarsEyebrow")}
  103. title={t("pillarsTitle")}
  104. align="center"
  105. />
  106. <div className="mt-14 grid gap-8 md:grid-cols-3">
  107. {pillars.map((p) => {
  108. const Icon = p.icon;
  109. return (
  110. <div
  111. key={p.title}
  112. className="ui-interactive-card group shadow-card rounded-3xl border border-slate-200/90 bg-white p-8"
  113. >
  114. <div
  115. className={`flex h-14 w-14 items-center justify-center rounded-2xl bg-gradient-to-br ${p.accent} text-white shadow-lg`}
  116. >
  117. <Icon className="h-7 w-7" aria-hidden />
  118. </div>
  119. <h3 className="font-serif mt-6 text-xl font-bold text-[var(--navy)]">{p.title}</h3>
  120. <p className="mt-3 text-sm leading-relaxed text-slate-600">{p.desc}</p>
  121. </div>
  122. );
  123. })}
  124. </div>
  125. </section>
  126. {/* 精选课程 */}
  127. <section className="ui-enter ui-enter-delay-2 border-y border-slate-200/90 bg-gradient-to-b from-slate-50/80 to-white py-20">
  128. <div className="site-container">
  129. <div className="flex flex-col items-start justify-between gap-6 md:flex-row md:items-end">
  130. <div className="min-w-0 flex-1">
  131. <SectionHeading
  132. eyebrow={t("featuredEyebrow")}
  133. title={t("featuredTitle")}
  134. align="left"
  135. />
  136. </div>
  137. <Link
  138. href="/courses"
  139. className="ui-interactive-btn shrink-0 rounded-full border-2 border-blue-600 px-6 py-2.5 text-sm font-bold text-blue-700 transition hover:bg-blue-600 hover:text-white"
  140. >
  141. {t("viewAll")}
  142. </Link>
  143. </div>
  144. <div className="mt-12 grid gap-8 md:grid-cols-2 lg:grid-cols-3">
  145. {featured.map((c) => (
  146. <Link
  147. key={c.slug}
  148. href={`/courses?cat=${c.category}`}
  149. className="ui-interactive-card group shadow-card overflow-hidden rounded-3xl border border-slate-200/90 bg-white"
  150. >
  151. <div className="relative h-36 overflow-hidden">
  152. {/* eslint-disable-next-line @next/next/no-img-element */}
  153. <img
  154. src={featuredCoverMap[c.category]}
  155. alt={c.title}
  156. className="absolute inset-0 h-full w-full object-cover transition duration-500 group-hover:scale-105"
  157. />
  158. <span className="absolute right-4 top-4 rounded-full bg-white/95 px-3 py-1 text-xs font-bold text-slate-800 shadow-sm">
  159. {tc("lessons", { count: c.lessonCount })}
  160. </span>
  161. </div>
  162. <div className="p-6">
  163. <h3 className="font-serif text-lg font-bold text-[var(--navy)] transition group-hover:text-blue-700">
  164. {c.title}
  165. </h3>
  166. <p className="mt-2 line-clamp-2 text-sm leading-relaxed text-slate-600">
  167. {c.subtitle}
  168. </p>
  169. <span className="mt-4 inline-flex items-center text-sm font-semibold text-blue-600">
  170. {tc("detail")}
  171. <span className="ml-1 transition group-hover:translate-x-0.5">→</span>
  172. </span>
  173. </div>
  174. </Link>
  175. ))}
  176. </div>
  177. </div>
  178. </section>
  179. {/* CTA 带 */}
  180. <section className="ui-enter ui-enter-delay-3 site-container section-block">
  181. <div className="relative overflow-hidden rounded-[2rem] bg-gradient-to-r from-blue-700 via-blue-800 to-indigo-900 px-8 py-14 text-center text-white shadow-xl shadow-blue-900/20 md:px-16">
  182. <div className="pointer-events-none absolute -right-24 -top-24 h-64 w-64 rounded-full bg-white/10 blur-3xl" />
  183. <div className="pointer-events-none absolute -bottom-16 -left-16 h-48 w-48 rounded-full bg-amber-400/20 blur-3xl" />
  184. <h2 className="font-serif relative text-2xl font-bold md:text-3xl">{t("ctaBandTitle")}</h2>
  185. <p className="relative mx-auto mt-4 max-w-2xl text-slate-200">
  186. {t("ctaBandSubtitle")}
  187. </p>
  188. <div className="relative mt-10 flex flex-wrap justify-center gap-4">
  189. <Link
  190. href="/courses"
  191. className="ui-interactive-btn inline-flex rounded-full bg-white px-8 py-3.5 text-sm font-bold text-blue-900 shadow-lg transition hover:bg-amber-50"
  192. >
  193. {t("ctaBandPrimary")}
  194. </Link>
  195. <Link
  196. href="/contact"
  197. className="ui-interactive-btn inline-flex rounded-full border-2 border-white/40 px-8 py-3.5 text-sm font-semibold text-white transition hover:bg-white/10"
  198. >
  199. {t("ctaBandSecondary")}
  200. </Link>
  201. </div>
  202. </div>
  203. </section>
  204. </div>
  205. );
  206. }